global sierpinski_asm

section .data

maximoPixeles: DD 255.00, 255.00, 255.00, 255.00
uno: DD 1
   
section .text

;void sierpinski_asm (unsigned char *src,
;                     unsigned char *dst,
;                     int cols, int rows,
;                     int src_row_size,
;                     int dst_row_size)
; unsigned char *src -> rdi
; unsigned char *dst -> rsi
; int cols           -> edx
; int rows           -> ecx
; int src_row_size   -> r8d
; int dst_row_size   -> r9d

%define rows r12d
%define cols r13
%define src r14
%define dst r15

sierpinski_asm:
    
    push rbp
    mov rbp, rsp

    push r15
    push r14
    push r13
    push r12
    push rbx
    sub rsp, 8

    mov edx, edx

    mov src, rdi
    mov dst, rsi
    mov rows, ecx
    mov cols, rdx

    movd xmm2, rows ; xmm2 = * | * | * | rows(cantFilas)
    pshufd xmm2, xmm2, 0h ; xmm2 = rows | rows | rows | rows
    cvtdq2ps xmm2, xmm2 ; datos en floats
    movd xmm3, edx ; xmm3 = * | * | * | cols (cantCols)
    pshufd xmm3, xmm3, 0h ; xmm3 = cols | cols | cols | cols
    cvtdq2ps xmm3, xmm3 ; datos en floats
    movdqu xmm4, [maximoPixeles] ; xmm4 = 255.0 | 255.0 | 255.0 | 255.0
    movd xmm6, [uno] ; xmm6 = * | * | * | 1
    pshufd xmm6, xmm6, 0h ; xmm6 = 1 | 1 | 1 | 1
    cvtdq2ps xmm6, xmm6 ; datos en floats
    divps xmm6, xmm4 ; xmm6 = 1 / 255.0 | 1 / 255.0 | 1 / 255.0 | 1 / 255.0

    sal cols, 2 ; multiplico las columnas por 4

    xor eax, eax ; uso eax como contador de las filas (i)
    .loop_filas:
        xor rdx, rdx ; uso rdx como contador de las columnas por byte (j)
        xor rbx, rbx ; uso rbx como contador de las columnas por pixel (k)
        movd xmm1, eax  ; xmm1 = * | * | * | i 
        pshufd xmm1, xmm1, 0h ; xmm1 = i | i | i | i
        cvtdq2ps xmm1, xmm1 ; datos en floats
        divps xmm1, xmm2 ; xmm1 = i / rows | i / rows | i / rows | i / rows
        mulps xmm1, xmm4 ; xmm1 = (i / rows) * 255.0 | (i / rows) * 255.0 | (i / rows) * 255.0 | (i / rows) * 255.0
     	cvttps2dq xmm1, xmm1 ; valores pasados a int con truncamiento
        .loop_columnas:
        	; PRIMERO COEFICIENTE
            movd xmm5, ebx  ; xmm5 = * | * | * | k 
        	pshufd xmm5, xmm5, 0h ; xmm5 = k | k | k | k
        	cvtdq2ps xmm5, xmm5 ; datos en floats
        	divps xmm5, xmm3 ; xmm5 = k / cols | k / cols | k / cols | k / cols
        	mulps xmm5, xmm4 ; xmm5 = (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0
     		cvttps2dq xmm5, xmm5 ; valores pasados a int con truncamiento
     		movdqu xmm7, xmm1 ; xmm7 = xmm1
     		pxor xmm7, xmm5 ; xmm7 = ((int)(i / rows) * 255.0) XOR ((int)(k / cols) * 255.0))
     		cvtdq2ps xmm7, xmm7 ; datos en floats xmm7 
     		mulps xmm7, xmm6  ; xmm7 = (1 / 255.0) * ((i / rows) * 255.0) XOR ((k / cols) * 255.0)
            ; SEGUNDO COEFICIENTE
            inc ebx
            movd xmm5, ebx  ; xmm5 = * | * | * | k 
            pshufd xmm5, xmm5, 0h ; xmm5 = k | k | k | k
            cvtdq2ps xmm5, xmm5 ; datos en floats
            divps xmm5, xmm3 ; xmm5 = k / cols | k / cols | k / cols | k / cols
            mulps xmm5, xmm4 ; xmm5 = (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0
            cvttps2dq xmm5, xmm5 ; valores pasados a int con truncamiento
            movdqu xmm8, xmm1 ; xmm8 = xmm1
            pxor xmm8, xmm5 ; xmm8 = ((int)(i / rows) * 255.0) XOR ((int)(k / cols) * 255.0))
            cvtdq2ps xmm8, xmm8 ; datos en floats xmm8
            mulps xmm8, xmm6  ; xmm8 = (1 / 255.0) * ((i / rows) * 255.0) XOR ((k / cols) * 255.0)
            ; TERCER COEFICIENTE
            inc ebx
            movd xmm5, ebx  ; xmm5 = * | * | * | k 
            pshufd xmm5, xmm5, 0h ; xmm5 = k | k | k | k
            cvtdq2ps xmm5, xmm5 ; datos en floats
            divps xmm5, xmm3 ; xmm5 = k / cols | k / cols | k / cols | k / cols
            mulps xmm5, xmm4 ; xmm5 = (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0
            cvttps2dq xmm5, xmm5 ; valores pasados a int con truncamiento
            movdqu xmm9, xmm1 ; xmm9 = xmm1
            pxor xmm9, xmm5 ; xmm9 = ((int)(i / rows) * 255.0) XOR ((int)(k / cols) * 255.0))
            cvtdq2ps xmm9, xmm9 ; datos en floats xmm9
            mulps xmm9, xmm6  ; xmm9 = (1 / 255.0) * ((i / rows) * 255.0) XOR ((k / cols) * 255.0)
            ; CUARTO COEFICIENTE
            inc ebx
            movd xmm5, ebx  ; xmm5 = * | * | * | k 
            pshufd xmm5, xmm5, 0h ; xmm5 = k | k | k | k
            cvtdq2ps xmm5, xmm5 ; datos en floats
            divps xmm5, xmm3 ; xmm5 = k / cols | k / cols | k / cols | k / cols
            mulps xmm5, xmm4 ; xmm5 = (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0 | (k / cols) * 255.0
            cvttps2dq xmm5, xmm5 ; valores pasados a int con truncamiento
            movdqu xmm10, xmm1 ; xmm10 = xmm1
            pxor xmm10, xmm5 ; xmm10 = ((int)(i / rows) * 255.0) XOR ((int)(k / cols) * 255.0))
            cvtdq2ps xmm10, xmm10 ; datos en floats xmm10
            mulps xmm10, xmm6  ; xmm10 = (1 / 255.0) * ((i / rows) * 255.0) XOR ((k / cols) * 255.0)
            ; CAMBIO DATOS: PASO DE BYTE A DWORD      
            movdqu xmm0, [src + rdx] ; bytes a cambiar (son de tamaño 1 byte)
            xorps xmm5, xmm5
            movdqu xmm11, xmm0
            punpcklbw xmm0, xmm5; de bytes a words parte baja
            punpckhbw xmm11, xmm5 ; de bytes a words parte alta
            movdqu xmm13, xmm0
            movdqu xmm12, xmm11
            punpcklwd xmm0, xmm5  ; en xmm0  tengo el pixel 1 en DW
            punpckhwd xmm13, xmm5 ; en xmm13 tengo el pixel 2 en DW
            punpcklwd xmm11, xmm5 ; en xmm11 tengo el pixel 3 en DW
            punpckhwd xmm12, xmm5 ; en xmm12 tengo el pixel 4 en DW
            cvtdq2ps xmm0, xmm0   ; paso a float
            cvtdq2ps xmm13, xmm13 ; paso a float
            cvtdq2ps xmm11, xmm11 ; paso a float
            cvtdq2ps xmm12, xmm12 ; paso a float
            ; MULTIPLICO POR SU COEFICIENTE
            mulps xmm0, xmm7  
            mulps xmm13, xmm8  
            mulps xmm11, xmm9
            mulps xmm12, xmm10
			cvttps2dq xmm0, xmm0   ; paso los datos de float a int truncando
            cvttps2dq xmm13, xmm13 ; paso los datos de float a int truncando
            cvttps2dq xmm11, xmm11 ; paso los datos de float a int truncando
            cvttps2dq xmm12, xmm12 ; paso los datos de float a int truncando
            ; PASO DE DWORD A BYTE
            packusdw xmm0, xmm13 ; xmm0 = pixel 2 | pixel 1
            packusdw xmm11, xmm12 ; xmm11 = pixel 4 | pixel 3
            packuswb xmm0, xmm11 ; xmm0 = pixel 4 | pixel 3 | pixel 2 | pixel 1
            movdqu [dst + rdx], xmm0 ; muevo los bytes al destino
            add rdx, 16 ; avanzo a la proximo columna de pixeles
            inc ebx ; incremento el k
            cmp rdx, cols
            jne .loop_columnas
        
        inc eax
        add src, cols
        add dst, cols
        cmp eax, rows
        jl .loop_filas

    add rsp, 8
    pop rbx
    pop r12
    pop r13
    pop r14
    pop r15
    pop rbp
    ret















